package snapex.feeclouds.controller;


import java.net.URLEncoder;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.validation.constraints.NotNull;

import org.apache.http.util.TextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.google.common.collect.Lists;

import lombok.extern.slf4j.Slf4j;
import snapex.feeclouds.model.resp.ErrorResps;
import snapex.feeclouds.utils.AppPropertyUtils;
import snapex.feeclouds.utils.AppUitls;
import snapex.feeclouds.utils.DateUtils;
import snapex.feeclouds.utils.DoubleUtils;
import snapex.feeclouds.utils.HttpHelper;
import snapex.feeclouds.utils.Md5;
import snapex.feeclouds.utils.ResponseContent;

@Slf4j
public class MainController {

    private static final Logger logger = LoggerFactory.getLogger(MainController.class);

    private static final String FOUR_CHECK_URL = "https://www.feeclouds.com/api/v2/invoice/check";//发票四要素查验接口
    private static final String OCR_CHECK_URL = "https://www.feeclouds.com/api/v3/ocr/check";//发票图像识别查验接口
    private static final String INVOICE_URL = "https://www.feeclouds.com/api/v1/invoice";//获取费耘发票接口
    private static final String INVOICE_SYNC_URL = "https://www.feeclouds.com/api/v1/invoice/sync";//标记发票已获取接口
    private static final String ABNORMAL_REMINDER_URL = "https://www.feeclouds.com/api/v1/abnormal/reminder";//获取国税查验状态通知接口
    private static final String RECEIVE_BATCH_URL = "https://www.feeclouds.com/api/v1/invoice/receive";//批量发票签收接口
    private static final String RECEIVE_SINGLE_URL = "https://www.feeclouds.com/api/v1/invoice/receive/single";//单张发票签收接口
    private static final String DEDUCTION_RESULT_URL = "https://www.feeclouds.com/api/v2/deduction/result";//获取进项发票接口
    private static final String DEDUCTION_URL = "https://www.feeclouds.com/api/v2/deduction";//进项发票认证接口

    private static final int HTTP_GET = 0;
    private static final int HTTP_POST = 1;

    /**
     * 此Demo未校验发票类型,请自行判断是传金额还是传校验码
     * fpdm: 发票代码 必填
     * fphm: 发票号码 必填
     * kprq: 开票日期 必填
     * je: 金额 非必填
     * jym: 校验码 非必填
     */
    @RequestMapping("/v2/invoice/check")
    public Object check(@RequestParam("fpdm") String fpdm,
                        @RequestParam("fphm") String fphm,
                        @RequestParam("kprq") String kprq,
                        String je,String jym
        ) {
        jym = jym == null ? "" : jym;

        //参数校验
        if (TextUtils.isEmpty(fpdm)
                || TextUtils.isEmpty(kprq)
                || TextUtils.isEmpty(fphm)) {
            return ErrorResps.PARAM_ERROR.get();
        } else if (!TextUtils.isEmpty(jym) && jym.length() != 20 && jym.length() != 6) {
            return ErrorResps.JYM_ERROR.get();
        }

        String formatJe = "";
        if (!TextUtils.isEmpty(je)) {
            try {
                formatJe = DoubleUtils.round2Str(Double.valueOf(je), 2);
            } catch (Exception e) {
                return ErrorResps.PARAM_ERROR.get();
            }
        }


        String content;
        try {
            content = ",," + fpdm + "," + fphm + "," +
                    formatJe + "," + DateUtils.yyyyMMdd.format(
                    DateUtils.date_sdf.parse(kprq)) + "," +
                    jym + ",";
        } catch (ParseException e) {
            return ErrorResps.PARAM_ERROR.get();
        }

        Map<String, String> kvMap = new HashMap<>();
        kvMap.put("content", content);

        return invokeFee(kvMap, null, FOUR_CHECK_URL, HTTP_POST);
    }

    /**
     * 发票图像识别查验接口
     *
     * @param fileData 图像只支持图片类型的文件，参数格式为图像的url或者base64编码的文件流
     * @return BaseResp
     */
    @RequestMapping("v3/ocr/check")
    public Object ocrCheck(@RequestParam(value = "file_data") String fileData,
                           @RequestParam(value = "is_check", required = false) String isCheck,//0：不查验，1：查验
                           @RequestParam(value = "department_id", required = false) String departmentId,//部门id
                           @RequestParam(value = "user_id", required = false) String userId,//用户id
                           @RequestParam(value = "memo", required = false) String memo//备注
    ) {

        Map<String, String> kvMap = new HashMap<>();
        kvMap.put("is_check", isCheck);

        if (!TextUtils.isEmpty(departmentId)) kvMap.put("department_id", departmentId);
        if (!TextUtils.isEmpty(userId)) kvMap.put("user_id", userId);
        if (!TextUtils.isEmpty(memo)) kvMap.put("memo", memo);

        HashMap<String, Object> ignore = new HashMap<>();
        ignore.put("file_data", fileData);

        return invokeFee(kvMap, ignore, OCR_CHECK_URL, HTTP_POST);

    }

    @RequestMapping("v1/invoice")
    public Object queryInvoice(@RequestParam(value = "page_size", required = false) String page_size,
                               @RequestParam(value = "page_num", required = false) String page_num,
                               @RequestParam(value = "department_ids", required = false) String department_ids,
                               @RequestParam(value = "invoiceid", required = false) String invoiceid,//需要获取的发票的id
                               @RequestParam(value = "start_time", required = false) String start_time,//发票查验起始时间
                               @RequestParam(value = "end_time", required = false) String end_time,//发票查验结束时间
                               @RequestParam(value = "state", required = false ) String state,//发票状态标识，已提交为"2"，已导出为"3"，已删除为"4"，不指定的情况下默认是"2,3"
                               @RequestParam(value = "user_id", required = false) String userId//用户id
    ) {

        Map<String, String> kvMap = new HashMap<>();

        if (!TextUtils.isEmpty(page_size)) kvMap.put("page_size", page_size);
        if (!TextUtils.isEmpty(page_num)) kvMap.put("page_num", page_num);
        if (!TextUtils.isEmpty(state)) kvMap.put("state", state);
        if (!TextUtils.isEmpty(department_ids)) kvMap.put("department_id", department_ids);
        if (!TextUtils.isEmpty(userId)) kvMap.put("user_id", userId);
        if (!TextUtils.isEmpty(invoiceid)) kvMap.put("invoiceid", invoiceid);
        if (!TextUtils.isEmpty(start_time)) kvMap.put("start_time", start_time);
        if (!TextUtils.isEmpty(end_time)) kvMap.put("end_time", end_time);

        return invokeFee(kvMap, null, INVOICE_URL, HTTP_GET);

    }

    @RequestMapping("v1/invoice/sync")
    public Object invoiceSync(@RequestParam(value = "invoiceid") String invoiceid
    ) {

        Map<String, String> kvMap = new HashMap<>();
        kvMap.put("invoiceid", invoiceid);

        return invokeFee(kvMap, null, INVOICE_SYNC_URL, HTTP_POST);
    }


    @RequestMapping("v1/abnormal/reminder")
    public Object abnormalReminder(@RequestParam(value = "status", required = false) String status) {
        //status: 获取各地区国税查验状态，此字段为非必传字段，不传此字段时，仅返回查验异常地区的列表
        //          1：仅获取查验异常地区列表
        //          999：获取全部地区列表及其状态

        Map<String, String> kvMap = new HashMap<>();
        if (!TextUtils.isEmpty(status)) kvMap.put("status", status);

        return invokeFee(kvMap, null, ABNORMAL_REMINDER_URL, HTTP_GET);
    }

    @RequestMapping("v1/invoice/receive")
    public Object invoiceReceive(@RequestParam("fpdm_fphm") String fpdm_fphm,
                                 @RequestParam("department_id") String department_id,
                                 @RequestParam("receive_state") String receive_state,
                                 @RequestParam("user_id") String user_id
    ) {


        Map<String, String> kvMap = new HashMap<>();
        kvMap.put("fpdm_fphm", fpdm_fphm);
        kvMap.put("department_id", department_id);
        kvMap.put("receive_state", receive_state);
        kvMap.put("user_id", user_id);

        return invokeFee(kvMap, null, RECEIVE_BATCH_URL, HTTP_POST);
    }

    @RequestMapping("v1/invoice/receive/single")
    public Object receiveSingle(@RequestParam("fpdm") String fpdm,
                                @RequestParam("fphm") String fphm,
                                @RequestParam("department_id") String department_id,
                                @RequestParam("receive_state") String receive_state,
                                @RequestParam("user_id") String user_id
    ) {


        Map<String, String> kvMap = new HashMap<>();
        kvMap.put("fpdm", fpdm);
        kvMap.put("fphm", fphm);
        kvMap.put("department_id", department_id);
        kvMap.put("receive_state", receive_state);
        kvMap.put("user_id", user_id);

        return invokeFee(kvMap, null, RECEIVE_SINGLE_URL, HTTP_POST);
    }

    @RequestMapping("v2/deduction/result")
    public Object deductionResult(@RequestParam(value = "page_size", required = false ) String page_size,
                                  @RequestParam(value = "page_num", required = false ) String page_num,
                                  @RequestParam("tax_no") String tax_no,
                                  @RequestParam(value = "fpdm", required = false) String fpdm,
                                  @RequestParam(value = "fphm", required = false) String fphm,
                                  @RequestParam(value = "fpzt", required = false) String fpzt,
                                  @RequestParam(value = "inv_start_date", required = false) String inv_start_date,
                                  @RequestParam(value = "inv_end_date", required = false) String inv_end_date,
                                  @RequestParam(value = "tax_period", required = false) String tax_period,
                                  @RequestParam(value = "received_start_date", required = false) String received_start_date,
                                  @RequestParam(value = "received_end_date", required = false) String received_end_date,
                                  @RequestParam(value = "deduction_start_date", required = false) String deduction_start_date,
                                  @RequestParam(value = "deduction_end_date", required = false) String deduction_end_date,
                                  @RequestParam(value = "received_user_id", required = false) String received_user_id,
                                  @RequestParam(value = "received_state", required = false) String received_state,
                                  @RequestParam(value = "deduction_state", required = false) String deduction_state
    ) {


        Map<String, String> kvMap = new HashMap<>();
        kvMap.put("tax_no", tax_no);

        if (!TextUtils.isEmpty(page_size)) kvMap.put("page_size", page_size);
        if (!TextUtils.isEmpty(page_num)) kvMap.put("page_num", page_num);
        if (!TextUtils.isEmpty(fpdm)) kvMap.put("fpdm", fpdm);
        if (!TextUtils.isEmpty(fphm)) kvMap.put("fphm", fphm);
        if (!TextUtils.isEmpty(fpzt)) kvMap.put("fpzt", fpzt);
        if (!TextUtils.isEmpty(inv_start_date)) kvMap.put("inv_start_date", inv_start_date);
        if (!TextUtils.isEmpty(inv_end_date)) kvMap.put("inv_end_date", inv_end_date);
        if (!TextUtils.isEmpty(tax_period)) kvMap.put("tax_period", tax_period);
        if (!TextUtils.isEmpty(received_start_date)) kvMap.put("received_start_date", received_start_date);
        if (!TextUtils.isEmpty(received_end_date)) kvMap.put("received_end_date", received_end_date);
        if (!TextUtils.isEmpty(deduction_start_date)) kvMap.put("deduction_start_date", deduction_start_date);
        if (!TextUtils.isEmpty(deduction_end_date)) kvMap.put("deduction_end_date", deduction_end_date);
        if (!TextUtils.isEmpty(received_user_id)) kvMap.put("received_user_id", received_user_id);
        if (!TextUtils.isEmpty(received_state)) kvMap.put("received_state", received_state);
        if (!TextUtils.isEmpty(deduction_state)) kvMap.put("deduction_state", deduction_state);

        return invokeFee(kvMap, null, DEDUCTION_RESULT_URL, HTTP_GET);
    }

    @RequestMapping("v2/deduction")
    public Object deduction(@RequestParam("fpdm") String fpdm,
                            @RequestParam("fphm") String fphm,
                            @RequestParam("tax_no") String tax_no,
                            @RequestParam("tax_period") String tax_period,
                            @RequestParam(value = "user_id", required = false) String user_id,
                            @RequestParam(value = "callback_url", required = false) String callback_url
    ) {


        Map<String, String> kvMap = new HashMap<>();
        kvMap.put("fpdm", fpdm);
        kvMap.put("fphm", fphm);
        kvMap.put("tax_no", tax_no);

        if (!TextUtils.isEmpty(tax_period)) kvMap.put("tax_period", tax_period);
        if (!TextUtils.isEmpty(user_id)) kvMap.put("user_id", user_id);
        if (!TextUtils.isEmpty(callback_url)) kvMap.put("callback_url", callback_url);

        return invokeFee(kvMap, null, DEDUCTION_URL, HTTP_POST);
    }

    /**
     * 调用fee通用方法
     *
     * @param kvMap 排除security,nonce_str之外的上送参数
     * @param httpPost
     * @return 包含sign的参数map
     */
    private static Object invokeFee(@NotNull Map<String, String> kvMap,
                                    @NotNull Map<String, Object> ignore,//不参与加密数据
                                    @NotNull String url,
                                    int method) {
        kvMap.put("company_key", AppPropertyUtils.getKey());
        //6位随机字符串
        kvMap.put("nonce_str", AppUitls.randomStr(6));

        Map<String, Object> resultMap = new HashMap<>();
        ArrayList<String> keys = Lists.newArrayList(kvMap.keySet());
        Collections.sort(keys);
        try {
            StringBuilder params = new StringBuilder();
            for (String key : keys) {
                params.append(key);
                params.append("=");
                params.append(kvMap.get(key));
                params.append("&");
                resultMap.put(key, kvMap.get(key).toString());
            }
            params.append(URLEncoder.encode("company_secret", "utf-8"));
            params.append("=");
            params.append(URLEncoder.encode(AppPropertyUtils.getSecret(), "utf-8"));

//            logger.info("参数排序后为: " + params.toString());
            String md5 = Md5.getEncode(params.toString());
            resultMap.put("sign", md5);
//            logger.info("======>>加密后签名: " + md5);
        } catch (Exception e) {
            logger.error("======>>签名失败:", e);
            return ErrorResps.SIGN_ERROR.get();
        }

        if (ignore != null) resultMap.putAll(ignore);
        Object content = null;
        try {
            if(method==HTTP_GET){
            	content = HttpHelper.doGetEntity(url, resultMap);
//                String entity = HttpHelper.doGetEntity(url, resultMap);
//                content = new JacksonJsonParser().parseMap(entity);
            }else{
                ResponseContent postEntity = HttpHelper.postEntity(url, resultMap);
//                content = new JacksonJsonParser().parseMap(postEntity.getContent());
                content = postEntity.getContent();
            }
           // logger.info("feeclouds reponse: " +content);
        } catch (Exception e) {
            logger.error("invoke feecloud failed: ", e);
            return ErrorResps.INVOKE_FEECLOUD_FAILED.get();
        }

//        logger.info("======费耘返回数据:{} ", content);

        return content;
    }

}
